/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package onpu_dms_xls.kernel;

import onpu_dms_xls.exceptions.MyException;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import onpu_dms_xls.exceptions.MySQLException;
import onpu_dms_xls.exceptions.MyXMLException;
import onpu_dms_xls.kernel.common.Util;
import onpu_dms_xls.kernel.common.VariableDeclaration;
import onpu_dms_xls.kernel.common.VariableType_DBRelationTypes;
import onpu_dms_xls.kernel.common.VariableType_InputRelationTypes;
import onpu_dms_xls.kernel.common.VariableType_XLSVisibilityTypes;
import onpu_dms_xls.kernel.common.inputParameters.FromDB_InputParameters;
import onpu_dms_xls.kernel.common.pdf.PDF_Label;
import onpu_dms_xls.kernel.common.pdf.PDF_TextLabelData;
import onpu_dms_xls.kernel.common.pdf.PDF_Extract_MarkLabels;
import onpu_dms_xls.kernel.common.pdf.PDF_Extract_LayoutTemplate;
import onpu_dms_xls.kernel.common.vipiska.*;
import onpu_dms_xls.kernel.common.inputParameters.Variable;
import onpu_dms_xls.kernel.common.logAndDebug.LoggingFacade;
import org.apache.log4j.Logger;

/**
 *
 * @author snbm
 */
public class PDF_Extract_Creator {
    

    private String fileName;
    private PDF_Extract_LayoutTemplate pdf_temlateAndData;
    private VariableDeclaration[] varDeclArr;
    FromDB_InputParameters input;
    Connection con;
    private static final HashMap<Integer, Double> fontsAndTheirSizesIn_ppt = new HashMap<Integer, Double>();
    private static final HashMap<Integer, Double> CAPS_fontsAndTheirSizesIn_ppt = new HashMap<Integer, Double>();

    public PDF_Extract_Creator(String fileName, PDF_Extract_LayoutTemplate pdf_temlateAndData,
            VariableDeclaration[] varDeclArr, FromDB_InputParameters input, Connection con) {
        LoggingFacade.trace.info("PDF_Extract_Creator constructor, fileName = " + fileName);
        this.fileName = new String(fileName);
        this.pdf_temlateAndData = pdf_temlateAndData;
        this.varDeclArr = varDeclArr;
        this.input = input;
        this.con = con;
        fontsAndTheirSizesIn_ppt.put(7, 4.1);
        fontsAndTheirSizesIn_ppt.put(8, 4.75);
        fontsAndTheirSizesIn_ppt.put(9, 5.4);
        CAPS_fontsAndTheirSizesIn_ppt.put(9, 5.4);
        CAPS_fontsAndTheirSizesIn_ppt.put(8, 4.85);
        CAPS_fontsAndTheirSizesIn_ppt.put(7, 4.2);
        CAPS_fontsAndTheirSizesIn_ppt.put(6, 3.6);
        CAPS_fontsAndTheirSizesIn_ppt.put(5, 3.0);
    }

    public File makeFile() throws Exception {
        LoggingFacade.trace.info("\tmakeFile start");
        File res = null;
        res = new File(fileName);
        if (res.exists()) {
            res.delete();
            LoggingFacade.trace.info("\tmakeFile deleted existing file");
        }
        LoggingFacade.trace.info("\tmakeFile working further");
        try {
            if (!res.createNewFile()) {
                throw new MyException("PDF_Vipiska_Creator", "makeFile", "cannot create new .pdf");
            }
        } catch (Exception e) {
            //throw new MyException
        }


        PDF_TextLabelData[] labels = pdf_temlateAndData.getTextLabelDataArr().toArray(new PDF_TextLabelData[]{});
        PDF_Extract_MarkLabels markLabels = pdf_temlateAndData.getMarkLabels();

        LoggingFacade.trace.trace("\t\t\t markLabels="+markLabels);
        // step 1
        Document document = new Document(PageSize.A4.rotate());
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(fileName));
        // step 3
        document.open();
        // step 4
        document.addTitle("Виписка до диплому");

        //перша сторінка
        PdfContentByte pcb = writer.getDirectContentUnder();


        pcb.saveState();
        for (PDF_TextLabelData label : labels) {
            if (label.getPageNum() == 1) {
                //no virtual column alignment
                if (label.getVirtColLeftBorder() == 0 && label.getVirtColRightBorder() == 0) {
                    pcb.setFontAndSize(BaseFont.createFont(label.getFont(), label.getCodePage(), true), label.getFontSize());
                    pcb.beginText();
                    pcb.showTextAligned(PdfContentByte.ALIGN_LEFT, getVariableValueForLabel(label), label.getX(), label.getY(), 0);
                    pcb.endText();
                } //virtual column alignment - FOR MARKS!!!
                else {
                    throw new MyException("PDF_Vipiska_Creator", "makeFile", "unsupported multiColumn on the page with marks");
                }
            }
        }
        pcb.restoreState();


        //for marks.
        if (markLabels != null) {
            LoggingFacade.trace.trace("\t\tmarkLabels != null");
            pcb.saveState();
            final double MARKS_ONE_CHAR_SIZE = get_ONE_CHAR_SIZE(markLabels);
            int currentX = markLabels.getFirstNameColLeftBorder();
            double currentY = markLabels.getFirstColFirstLineY();
            int currentLeftBorder = markLabels.getFirstNameColLeftBorder();
            int currentRightBorder = markLabels.getFirstNameColRightBorder();
            int columnIndex = 1;

            pcb.setFontAndSize(BaseFont.createFont(markLabels.getFont(), markLabels.getCodePage(), true), markLabels.getFontSize());

            for (Extract_Subject subj : markLabels.getSubjects()) {
                ArrayList<String> words = getWordsFromString(subj.getFullName());
                int hours = subj.getHours();
                String mark = String.valueOf(subj.getMark());

                int lineLehgthInChars = (int) ((currentRightBorder - currentLeftBorder) / MARKS_ONE_CHAR_SIZE);

                boolean canWriteAndNoEndReached = checkForEndInMarksColumns(currentY, markLabels, words, lineLehgthInChars, columnIndex);

                if (canWriteAndNoEndReached) {

                    //hours
                    simplePrintAnyLabel(pcb, String.valueOf(hours), markLabels.getStudyHourX() + markLabels.getColumnDelta() * (columnIndex - 1), (int) (currentY) - 2);
                    //mark
                    simplePrintAnyLabel(pcb, mark, markLabels.getMarkX() + markLabels.getColumnDelta() * (columnIndex - 1), (int) (currentY) - 3);

                    int wordIndex = 0;
                    int lineIndex = 1;

                    LoggingFacade.trace.info("mark line for " + subj.getFullName());

                    while (true) {
                        if (lineIndex % 2 == 1) {
                            //1,3,5 lines
                            StringBuilder oddLine = new StringBuilder();
                            while (true) {
                                if (wordIndex == words.size()) {
                                    //для однолинейных предметов - вывожу немного ниже, с эстетической точки зрения
                                    //но только для однолинейных.
                                    if (lineIndex == 1) { //эта проверка, не лишняя, ибо тут может закончиться предмет 3 линейный
                                        simplePrintAnyLabel(pcb, oddLine.toString(), currentX, (int) currentY - 3);
                                    } else {
                                        simplePrintAnyLabel(pcb, oddLine.toString(), currentX, (int) currentY);
                                    }
                                    break;
                                }
                                if ((oddLine.length() + words.get(wordIndex).length()) > lineLehgthInChars) {
                                    simplePrintAnyLabel(pcb, oddLine.toString(), currentX, (int) currentY);
                                    break;
                                }
                                oddLine.append(words.get(wordIndex));
                                wordIndex++;
                            }
                            if (wordIndex == words.size()) {
                                currentY -= markLabels.getRowHeigh();
                                break;
                            } else {
                                lineIndex++;
                                if (columnIndex == 1) {
                                    currentY -= (markLabels.getFirstColFirstLineY() - markLabels.getFirstColSecondLineY());
                                } else {
                                    currentY -= (markLabels.getSecondAndThirdColFirstLineY() - markLabels.getSecondAndThirdColSecondLineY());
                                }
                            }
                        } else {
                            //2,4,6 lines
                            StringBuilder evenLine = new StringBuilder();
                            while (true) {
                                if (wordIndex == words.size()) {
                                    simplePrintAnyLabel(pcb, evenLine.toString(), currentX, (int) currentY);
                                    break;
                                }
                                if ((evenLine.length() + words.get(wordIndex).length()) > lineLehgthInChars) {
                                    simplePrintAnyLabel(pcb, evenLine.toString(), currentX, (int) currentY);
                                    break;
                                }
                                evenLine.append(words.get(wordIndex));
                                wordIndex++;
                            }
                            if (wordIndex == words.size()) {
                                if (columnIndex == 1) {
                                    currentY -= (markLabels.getFirstColSecondLineY() - (markLabels.getFirstColFirstLineY() - markLabels.getRowHeigh()));
                                } else {
                                    currentY -= (markLabels.getSecondAndThirdColSecondLineY() - (markLabels.getSecondAndThirdColFirstLineY() - markLabels.getRowHeigh()));
                                }
                                break;
                            } else {
                                lineIndex++;
                                if (columnIndex == 1) {
                                    currentY -= (markLabels.getFirstColSecondLineY() - (markLabels.getFirstColFirstLineY() - markLabels.getRowHeigh()));
                                } else {
                                    currentY -= (markLabels.getSecondAndThirdColSecondLineY() - (markLabels.getSecondAndThirdColFirstLineY() - markLabels.getRowHeigh()));
                                }
                            }
                        }
                    }
                } else {
                    LoggingFacade.trace.info("END OF COLUMN REACHED");
                    //установка параметров, чтобы следующие предметы выводились в следующей колонке
                    if (columnIndex == 1) {
                        //goto second column
                        currentX = markLabels.getFirstNameColLeftBorder() + markLabels.getColumnDelta();
                        currentY = markLabels.getSecondAndThirdColFirstLineY();
                        currentLeftBorder = markLabels.getFirstNameColLeftBorder() + markLabels.getColumnDelta();
                        currentRightBorder = markLabels.getFirstNameColRightBorder() + markLabels.getColumnDelta();
                        columnIndex = 2;
                    } else if (columnIndex == 2) {
                        //goto third column
                        currentX = markLabels.getFirstNameColLeftBorder() + markLabels.getColumnDelta() * 2;
                        currentY = markLabels.getSecondAndThirdColFirstLineY();
                        currentLeftBorder = markLabels.getFirstNameColLeftBorder() + markLabels.getColumnDelta() * 2;
                        currentRightBorder = markLabels.getFirstNameColRightBorder() + markLabels.getColumnDelta() * 2;
                        columnIndex = 3;
                    } else if (columnIndex == 3) {
                        LoggingFacade.trace.fatal("end of third column. Change your font size :-)");
                    }
                }
            }
            pcb.restoreState();
        }



        //друга сторінка
        document.newPage();
        pcb = writer.getDirectContentUnder();
        pcb.saveState();
        for (PDF_TextLabelData label : labels) {
            if (label.getPageNum() == 2) {
                //no virtual column alignment
                if (label.getVirtColLeftBorder() == 0 && label.getVirtColRightBorder() == 0) {
                    pcb.setFontAndSize(BaseFont.createFont(label.getFont(), label.getCodePage(), true), label.getFontSize());
                    simplePrintTextLabel(pcb, getVariableValueForLabel(label), label);
                } //virtual column alignment
                else {
                    //LoggingFacade.trace.info("\tmakeFile FUCK printing:"+label.getVariableName());
                    final double ONE_CHAR_SIZE = get_ONE_CHAR_SIZE(label);

                    ArrayList<String> words = getWordsFromString(getVariableValueForLabel(label));

                    System.out.println("first" + getVariableValueForLabel(label));
                    int firstLineLehgthInChars = (int) ((label.getVirtColRightBorder() - label.getX()) / ONE_CHAR_SIZE);
                    int wordIndex = 0;
                    StringBuilder firstLine = new StringBuilder();
                    while (true) {
                        if (wordIndex == words.size()) {
                            pcb.setFontAndSize(BaseFont.createFont(label.getFont(), label.getCodePage(), true), label.getFontSize());
                            simplePrintTextLabel(pcb, firstLine.toString(), label);
                            break;
                        }
                        if ((firstLine.length() + words.get(wordIndex).length()) > firstLineLehgthInChars) {
                            pcb.setFontAndSize(BaseFont.createFont(label.getFont(), label.getCodePage(), true), label.getFontSize());
                            simplePrintTextLabel(pcb, firstLine.toString(), label);
                            break;
                        }
                        firstLine.append(words.get(wordIndex));
                        wordIndex++;
                    }
                    if (wordIndex == words.size()) {
                        continue;
                    }

                    LoggingFacade.trace.trace("next" + getVariableValueForLabel(label));
                    //wordIndex here - the index of word to be inserted (NOT INSERTED yet)
                    //go to next lines
                    int nextLinesLengthInChars = (int) ((label.getVirtColRightBorder() - label.getVirtColLeftBorder()) / ONE_CHAR_SIZE);
                    int Y_linesAdjuster = 1;
                    double oneYColumnHigh = label.getOneYColumnHigh();

                    while (true) {
                        StringBuilder nextLine = new StringBuilder();
                        while (true) {
                            if (wordIndex == words.size()) {
                                pcb.setFontAndSize(BaseFont.createFont(label.getFont(), label.getCodePage(), true), label.getFontSize());
                                pcb.beginText();
                                pcb.showTextAligned(PdfContentByte.ALIGN_LEFT, nextLine.toString(), label.getVirtColLeftBorder(), (int) (label.getY() - Y_linesAdjuster * oneYColumnHigh), 0);
                                pcb.endText();
                                break;
                            }
                            if ((nextLine.length() + words.get(wordIndex).length()) > nextLinesLengthInChars) {
                                pcb.setFontAndSize(BaseFont.createFont(label.getFont(), label.getCodePage(), true), label.getFontSize());
                                pcb.beginText();
                                pcb.showTextAligned(PdfContentByte.ALIGN_LEFT, nextLine.toString(), label.getVirtColLeftBorder(), (int) (label.getY() - Y_linesAdjuster * oneYColumnHigh), 0);
                                pcb.endText();
                                break;
                            }
                            nextLine.append(words.get(wordIndex));
                            wordIndex++;
                        }
                        if (wordIndex == words.size()) {
                            break;
                        }
                        Y_linesAdjuster++;
                    }
                }
            }
        }
        pcb.restoreState();

        // step 5
        document.close();

        LoggingFacade.trace.info("\tmakeFile returning result");

        return res;
    }

    private String getVariableValueForLabel(PDF_Label label) {
        LoggingFacade.trace.info("getVariableValueForLabel call, labelName: " + label.getVariableName());

        for (VariableDeclaration vd : varDeclArr) {
            if (vd.getVarName().equals(label.getVariableName())) {
                LoggingFacade.trace.info("found corresponding variable declaration:" + vd.getVarName());
                LoggingFacade.trace.info("it's value: " + vd.getValue());
                return vd.getValue();
            }
        }
        throw new RuntimeException("not found corresponding variable declaration for label: " + label.getVariableName());
    }

    /**
    !!!!!!!!!!!! three lines only!!!!!!!!!!!!!
     */
    private boolean checkForEndInMarksColumns(
            double currentY,
            PDF_Extract_MarkLabels markLabels,
            ArrayList<String> words,
            int lineLehgthInChars,
            int columnIndex) {

        int wordIndex = 0;
        int lineIndex = 1;

        while (true) {
            if (lineIndex % 2 == 1) {
                //1,3,5 lines
                StringBuilder oddLine = new StringBuilder();
                while (true) {
                    if (wordIndex == words.size()) {
                        break;
                    }
                    if ((oddLine.length() + words.get(wordIndex).length()) > lineLehgthInChars) {
                        break;
                    }
                    oddLine.append(words.get(wordIndex));
                    wordIndex++;
                }
                if (wordIndex == words.size()) {
                    currentY -= markLabels.getRowHeigh();
                    break;
                } else {
                    lineIndex++;
                    if (columnIndex == 1) {
                        currentY -= (markLabels.getFirstColFirstLineY() - markLabels.getFirstColSecondLineY());
                    } else {
                        currentY -= (markLabels.getSecondAndThirdColFirstLineY() - markLabels.getSecondAndThirdColSecondLineY());
                    }
                }
            } else {
                //2,4,6 lines
                StringBuilder evenLine = new StringBuilder();
                while (true) {
                    if (wordIndex == words.size()) {
                        break;
                    }
                    if ((evenLine.length() + words.get(wordIndex).length()) > lineLehgthInChars) {
                        break;
                    }
                    evenLine.append(words.get(wordIndex));
                    wordIndex++;
                }
                if (wordIndex == words.size()) {
                    if (columnIndex == 1) {
                        currentY -= (markLabels.getFirstColSecondLineY() - (markLabels.getFirstColFirstLineY() - markLabels.getRowHeigh()));
                    } else {
                        currentY -= (markLabels.getSecondAndThirdColSecondLineY() - (markLabels.getSecondAndThirdColFirstLineY() - markLabels.getRowHeigh()));
                    }
                    break;
                } else {
                    lineIndex++;
                    if (columnIndex == 1) {
                        currentY -= (markLabels.getFirstColSecondLineY() - (markLabels.getFirstColFirstLineY() - markLabels.getRowHeigh()));
                    } else {
                        currentY -= (markLabels.getSecondAndThirdColSecondLineY() - (markLabels.getSecondAndThirdColFirstLineY() - markLabels.getRowHeigh()));
                    }
                }
            }
        }


        return (currentY > markLabels.getBottomY());
    }

    /**
    no fonts set, simple left alignment, print near X and Y
     */
    private void simplePrintAnyLabel(PdfContentByte pcb, String line, int X, int Y) {
        pcb.beginText();
        pcb.showTextAligned(PdfContentByte.ALIGN_LEFT, line, X, Y, 0);
        pcb.endText();
    }

    /**
    no fonts set, simple left alignment, print near X and Y
     */
    private void simplePrintTextLabel(PdfContentByte pcb, String line, PDF_TextLabelData label) {
        LoggingFacade.trace.info("\tmakeFile printing:" + label.getVariableName() + " with data: " + line);
        pcb.beginText();
        pcb.showTextAligned(PdfContentByte.ALIGN_LEFT, line, label.getX(), label.getY(), 0);
        pcb.endText();
    }

    private double get_ONE_CHAR_SIZE(PDF_Label label) {
        double res;
        if (label instanceof PDF_Extract_MarkLabels) {
            if (label.getFontSize() >= 5
                    && label.getFontSize() <= 9) {
                res = CAPS_fontsAndTheirSizesIn_ppt.get(new Integer(label.getFontSize()));
            } else {
                res = CAPS_fontsAndTheirSizesIn_ppt.get(7);
            }
            return res;
        }

        if (label.getFontSize() == 8 || label.getFontSize() == 9 || label.getFontSize() == 7) {
            res = fontsAndTheirSizesIn_ppt.get(new Integer(label.getFontSize()));
        } else {
            res = fontsAndTheirSizesIn_ppt.get(8);
        }
        return res;
    }

    /**
    separate by ' ' and '-'
     */
    private static ArrayList<String> getWordsFromString(String data) {
        ArrayList<String> res = new ArrayList<String>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < data.toCharArray().length; i++) {
            char currentChar = data.charAt(i);
            if (currentChar != ' '
                    && currentChar != '-'
                    && currentChar != ':') {
                sb.append(currentChar);
                if (i == data.toCharArray().length - 1) {
                    res.add(sb.toString());
                }
            } else {
                sb.append(currentChar);
                res.add(sb.toString());
                sb = new StringBuilder();
            }
        }
        return res;
    }

    /**
    головний метод отримання даних з БД.
    поки що стоїть заглушка
     */
    public void loadDataFromDBToVipiska_Data() throws MyException {
        //для змінних з значенням в input (0 рівень) - присвоїти ці значення
        //це все спеціально для student_id. більше нічого такого в мене поки немає.
        for (VariableDeclaration vd : varDeclArr) {
            if (!vd.isInIteration()
                    && vd.getVarType().getInput_Relation().equals(VariableType_InputRelationTypes.ALWAYS_IN_INPUT)
                    && vd.getVarType().getDB_Relation().equals(VariableType_DBRelationTypes.NONE)
                    && vd.getVarType().getXLS_Visibility().equals(VariableType_XLSVisibilityTypes.NOT_VISIBLE)) {

                LoggingFacade.trace.info("found 0 level variable (student_id): " + vd.getVarName());
                LoggingFacade.trace.info("finding a value in input for it;");
                for (Variable v : input.getOtherVars()) {
                    LoggingFacade.trace.info("\t" + v.getName());
                    if (v.getName().equals(vd.getVarName())) {
                        LoggingFacade.trace.info("found corresponding variable in input!!!!!!");
                        vd.setValue(v.getValue());
                        LoggingFacade.trace.info("new value for " + vd.getVarName() + " is " + vd.getValue());
                        break;
                    }
                }
            }
        }


        //тепер для змінних 0 рівня, зі значенням на основі запиту в БД
        //поки що тільки для kafedra_speciality_id
        for (VariableDeclaration vd : varDeclArr) {
            if (!vd.isInIteration()
                    && vd.getVarType().getInput_Relation().equals(VariableType_InputRelationTypes.NEVER_IN_INPUT)
                    && vd.getVarType().getDB_Relation().equals(VariableType_DBRelationTypes.SELECT)
                    && vd.getVarType().getXLS_Visibility().equals(VariableType_XLSVisibilityTypes.NOT_VISIBLE)) {

                LoggingFacade.trace.info("found 0 level variable (kafedra_speciality_id): " + vd.getVarName());

                //1. getQuery
                String fromDBQuery = vd.getFromDBQuery();
                //2. replace $ parameters
                LoggingFacade.trace.info("fromDBQuery BEFORE REPLACEMENT:" + fromDBQuery);
                fromDBQuery = Util.fillQueryWithVariablesValues(fromDBQuery, varDeclArr);
                LoggingFacade.trace.info("fromDBQuery AFTER REPLACEMENT:" + fromDBQuery);
                //3. execute Query, get variable value ----------temp - dataTypes things....
                String queryResult = "";
                try {
                    Statement st = con.createStatement();
                    ResultSet rs = st.executeQuery(fromDBQuery);
                    rs.next();
                    queryResult = rs.getString(1);

                } catch (SQLException e) {
                    LoggingFacade.trace.info("EXCEPTION:" + e.getMessage());

                    //that happens
                    if (e.getMessage().equals("ResultSet not positioned properly, perhaps you need to call next.")) {
                        queryResult = "n/d";
                    } else {
                        throw new MySQLException(
                                "PDF_Extract_Creator",
                                "loadDataFromDBToVipiska_Data",
                                fromDBQuery,
                                "",
                                e.getMessage());
                    }
                }
                LoggingFacade.trace.info("queryResult:" + queryResult);
                vd.setValue(queryResult);
                LoggingFacade.trace.info("new value for " + vd.getVarName() + " is " + vd.getValue());
            }
        }

        //тепер для змінних 1 рівня, просто ганяємо запити до БД...
        for (VariableDeclaration vd : varDeclArr) {
            if (!vd.isInIteration()
                    && vd.getVarType().getInput_Relation().equals(VariableType_InputRelationTypes.NEVER_IN_INPUT)
                    && vd.getVarType().getDB_Relation().equals(VariableType_DBRelationTypes.SELECT)
                    && vd.getVarType().getXLS_Visibility().equals(VariableType_XLSVisibilityTypes.VISIBLE)) {

                LoggingFacade.trace.info("found 1 level variable: " + vd.getVarName());

                //1. getQuery
                String fromDBQuery = vd.getFromDBQuery();
                //2. replace $ parameters
                LoggingFacade.trace.info("fromDBQuery BEFORE REPLACEMENT:" + fromDBQuery);
                fromDBQuery = Util.fillQueryWithVariablesValues(fromDBQuery, varDeclArr);
                LoggingFacade.trace.info("fromDBQuery AFTER REPLACEMENT:" + fromDBQuery);
                //3. execute Query, get variable value ----------temp - dataTypes things....
                String queryResult = "";
                try {
                    Statement st = con.createStatement();
                    ResultSet rs = st.executeQuery(fromDBQuery);
                    rs.next();
                    queryResult = rs.getString(1);

                } catch (SQLException e) {
                    //that happens
                    if (e.getMessage().equals("ResultSet not positioned properly, perhaps you need to call next.")) {
                        queryResult = "n/d";
                    } else {
                        throw new MySQLException(
                                "PDF_Extract_Creator",
                                "loadDataFromDBToVipiska_Data",
                                fromDBQuery,
                                "",
                                e.getMessage());
                    }
                }
                LoggingFacade.trace.info("queryResult:" + queryResult);
                vd.setValue(queryResult);
                LoggingFacade.trace.info("new value for " + vd.getVarName() + " is " + vd.getValue());
            }
        }



        //______________________________MARKSSSSSSSSSSSSS
        String fromDB_IterationRowQuery = null;

        ArrayList<VariableDeclaration> iterRowVarDecl = new ArrayList<VariableDeclaration>();

        for (VariableDeclaration varDec : varDeclArr) {
            if (varDec.isInIteration()
                    && varDec.getVarType().getInput_Relation().equals(VariableType_InputRelationTypes.NEVER_IN_INPUT)
                    && varDec.getVarType().getXLS_Visibility().equals(VariableType_XLSVisibilityTypes.VISIBLE)) {
                iterRowVarDecl.add(varDec);
                fromDB_IterationRowQuery = varDec.getIterationRowSingleFromDBQuery();
            }
        }

        if (iterRowVarDecl.size() == 0) {
            throw new MyXMLException(
                    "PDF_EXtract_Creator",
                    "getData....",
                    "no iterable variables found in variable declaration array, formed from template xml",
                    "");
        }

        if (fromDB_IterationRowQuery == null) {
            throw new RuntimeException(" NO ITERATION QUERY FOUND FOR ITERATION VARIABLES");
        }


        //2. replace $ parameters
        LoggingFacade.trace.info("fromDBQuery BEFORE REPLACEMENT:" + fromDB_IterationRowQuery);
        fromDB_IterationRowQuery = Util.fillQueryWithVariablesValues(fromDB_IterationRowQuery, varDeclArr);
        LoggingFacade.trace.info("fromDBQuery AFTER REPLACEMENT:" + fromDB_IterationRowQuery);

        LoggingFacade.trace.info("\t\t loadData1");
        //3. execute Query, get variable value ----------
        ResultSet rs;
        try {
            Statement st = con.createStatement();
            rs = st.executeQuery(fromDB_IterationRowQuery);
        } catch (SQLException e) {
            LoggingFacade.trace.error("PDF_Extract_Creator", e);
            throw new MySQLException(
                    "PDF_Extract_Creator",
                    "loadDataFromDBToVipiska_Data",
                    fromDB_IterationRowQuery,
                    "",
                    e.getMessage());
        }
        ArrayList<Extract_Subject> sub = new ArrayList<Extract_Subject>();
        //4. throw it to sub
        LoggingFacade.trace.info("\t\t loadData2");
        try {
            while (rs.next()) {
                int control_id = rs.getInt("control_id");
                String subjecName = rs.getString("name") == null ? "" : rs.getString("name");
                int hours = rs.getInt("hours");
                int mark = rs.getInt("mark");

                if (control_id == 3){
                    subjecName = "Курсова робота: " + subjecName;
                    hours = 30;
                } else if (control_id == 4){
                    hours = 60;
                }
                
                sub.add(new Extract_Subject(control_id, subjecName, hours, mark));
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        this.pdf_temlateAndData.getMarkLabels().setSubjects(sub);
        LoggingFacade.trace.info("\t\t loadData3");
    }
}
/*

//        vd.setDiplomSeries("СК");
//        vd.setDiplomNumber(41859614);
//        vd.setSurname("ГУЛІЙ");
//        vd.setNameAndSecondName("АНТОН СЕРГІЙОВИЧ");
//        vd.setBirthDate("7 березня 1989 року");
//        vd.setPreviousDiplomType(DIPLOM_TYPES.BACHELOR);
//        vd.setPreviousDiplomSeriesAndNumber("СК № 38576969");
//        vd.setUniversityName(UNIVERSITIES_NAMES.ONPU);
//        vd.setDiplomType(DIPLOM_TYPES.SPECIALIST);
//        vd.setStudyProgramType("Освітньо-професійна програма підготовки спеціаліста");
//        vd.setStudyDuration("10 місяців");
//        vd.setStudyForm(STUDY_FORMS.FULL_TIME);
//        vd.setSpeciality(SPECIALITIES.SKS_SPECIALIST);
//        vd.setPracticeTypesAndDurations("переддипломна - 8 тижнів");
//        vd.setAcademicRights(ACADEMIC_RIGHTS.spec);
//        vd.setProfeccionalRights(PROFECCIONAL_RIGHTS.spec);
//        vd.setAdmissionDate("1 вересня 2010 року");
//        vd.setEndDate("14 жовтня 2011 року");
//
//        vd.setUniversityType(UNIVERSITIES_TYPES.ONPU);
//        vd.setAdmissionForm(ADMISSION_FORMS.spec);
//        vd.setProgrammRequirements(PROGRAMM_REQUIREMENTS.common);
//        vd.setStudyLoad("загальна тривалість навчання 2214 год. у т.ч. "
//                + "аудиторні заняття - 1782 год., самостійна робота студента - 432 год.");
//        vd.setExamSystem(EXAM_SYSTEMS.common);
//        vd.setMarkSystem(MARKS_SYSTEMS.common);
//
//        vd.setHasDyplomWork(true);
//        vd.setDiplomWorkType(DIPLOM_WORK_TYPES.common);
//        vd.setDiplomWorkTheme("Підвищення ефективності низькошвидкісних мереж Інтернет");
//        vd.setDiplomMark(STRING_MARKS.SATISFYING);
//        vd.setPeriodToWriteDiplomWork("8 тижнів");
//
//        vd.setHasGOS(true);
//        vd.setGOS_Name(GOS_NAMES.SKS);
//        vd.setGOS_Mark(STRING_MARKS.GOOD);
//
//        vd.setSpecialityGainDate("14 жовтня 2011");
//        vd.setQualificationName(QUALIFICATION_NAMES.SKS_SPECIALIST);
//
//        vd.setCityName(CITIES_NAMES.ODESA);
//        vd.setVipiskaDate("30 листопада 2011");
//        vd.setDiplomRegNumber("766/11
//        vd.setSummaryHours(2214);


ArrayList<Vipiska_Subject> sub = new ArrayList<Vipiska_Subject>();
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих міжпланетних порталів для автоматизації транспортування незбалансованих індексів денормалізованих таблиць реляційних БД комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Переддипломна практика".toUpperCase(), 432, STRING_MARKS.VERY_GOOD));
sub.add(new Vipiska_Subject("Курсовий проект: Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 60, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Курсова робота: Проектування вбудованих компютерних систем".toUpperCase(), 30, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Цивільна оборона".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Автоматизовані електромеханічні системи або аналіз обчислювальних систем".toUpperCase(), 180, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Охорона праці в галузі".toUpperCase(), 54, STRING_MARKS.ZARAHOVANO));
sub.add(new Vipiska_Subject("Проектування спеціалізованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.SATISFYING));
sub.add(new Vipiska_Subject("Проектування вбудованих комп'ютерних систем".toUpperCase(), 252, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Спеціальні методи та засоби вимірювання".toUpperCase(), 144, STRING_MARKS.ENOUGH));
sub.add(new Vipiska_Subject("Програмне забезпечення спеціалізованих комп'ютерних систем".toUpperCase(), 144, STRING_MARKS.SATISFYING));
 */
